home *** CD-ROM | disk | FTP | other *** search
- ;;; -*- Mode:Lisp; Package:Weyli; Base:10; Lowercase:T; Syntax:Common-Lisp -*-
- ;;; ===========================================================================
- ;;; Expanded Polynomials
- ;;; ===========================================================================
- ;;; (c) Copyright 1989, 1991 Cornell University
-
- ;;; $Id: epolynomial.lisp,v 2.9 1991/11/04 16:11:54 rz Exp $
-
- (in-package "WEYLI")
-
- (defmethod make-epolynomial
- ((domain multivariate-polynomial-ring) compare-function (poly mpolynomial))
- (make-epolynomial domain compare-function (poly-form poly)))
-
- (defmethod make-epolynomial
- ((domain multivariate-polynomial-ring) compare-function (poly epolynomial))
- (if (eql compare-function (compare-function poly)) poly
- (make-instance 'epolynomial
- :domain domain
- :compare-function compare-function
- :form (sort (poly-form poly)
- #'(lambda (a b)
- (%funcall compare-function
- (first a) (first b)))))))
-
- (defmethod make-epolynomial
- ((domain multivariate-polynomial-ring) compare-function (form list))
- (let* ((dimension (length (ring-variables domain)))
- (evs (get-vector-space (get-lisp-numbers) dimension))
- poly-form)
- (labels ((scan-poly-form (form exp next-var)
- (cond ((poly-coef? form)
- (unless (0? form)
- (loop for i upfrom next-var below dimension
- do (push 0 exp))
- (push (cons (%apply #'make-element evs (reverse exp))
- form)
- poly-form)))
- (t (let ((var-index (poly-order-number form)))
- (loop for i upfrom next-var below var-index
- do (push 0 exp))
- (setq var-index (1+ var-index))
- (map-over-each-term (poly-terms form) (e c)
- (scan-poly-form c (cons e exp)
- var-index)))))))
- (scan-poly-form form () 0)
- (make-instance 'epolynomial
- :domain domain
- :compare-function compare-function
- :form (sort poly-form
- #'(lambda (a b)
- (%funcall compare-function
- (first a) (first b))))))))
-
- (defmethod print-object ((poly epolynomial) stream)
- (if (0? poly) (princ 0 stream)
- (with-slots (var-count) poly
- (let ((first? t)
- (variables (ring-variables (domain-of poly))))
- (map-over-each-term (poly-form poly) (e c)
- (cond ((minus? c)
- (setq c (minus c))
- (if (and (1? c) (not (0? e)))
- (princ " -" stream)
- (format stream " - ~S" c)))
- ((null first?)
- (if (and (1? c) (not (0? e)))
- (princ " + " stream)
- (format stream " + ~S" c)))
- (t (unless (and (1? c) (not (0? e)))
- (format stream "~S" c))))
- (loop for var in variables
- for i upfrom 0
- for exp = (ref e i) do
- (unless (lisp:zerop exp)
- (princ " " stream)
- (display var stream)
- (unless (eql 1 exp)
- (format stream "^~D" exp))))
- (setq first? nil))))))
-
- (defmethod 0? ((x epolynomial))
- (null (poly-form x)))
-
- (defmethod 1? ((x epolynomial))
- (let ((form (poly-form x)))
- (and (null (rest form))
- (0? (le form))
- (1? (lc form)))))
-
- ;;; ===========================================================================
- ;;; Polynomial Arithmetic
- ;;; ===========================================================================
-
- ;; Notice that we can use MAP-OVER-EACH-TERM since it doesn't depend
- ;; upon the exponent arithmetic, while UPDATE-TERMS does.
-
- (defmacro same-compare-functions ((x y) &body body)
- `(with-slots (compare-function) x
- (unless (eq compare-function (slot-value ,y 'compare-function))
- (error "EPolynomials don't have same compare function: ~S and ~S"
- ,x ,y))
- ,@body))
-
- ;; These should really check to make sure that the number of variables
- ;; hasn't changed.
- (defmethod-binary plus epolynomial (x y)
- (same-compare-functions (x y)
- (bind-domain-context domain
- (make-instance 'epolynomial
- :domain domain
- :compare-function compare-function
- :form (gterms-plus compare-function (poly-form x) (poly-form y))))))
-
- (defun gterms-plus (compare-function x y) ;x and y are term lists
- (let ((ans-terms (list nil))
- (terms nil)
- sum)
- (macrolet
- ((collect-term (.e. .c.)
- `(progn (setf (rest terms) (make-terms , .e. , .c.))
- (setf terms (rest terms)))))
- (setq terms ans-terms)
- (loop
- (cond ((terms0? x)
- (cond ((terms0? y) (return (rest ans-terms)))
- (t (collect-term (le y) (lc y))
- (setq y (red y)))))
- ((or (terms0? y)
- (%funcall compare-function (le x) (le y)))
- (collect-term (le x) (lc x))
- (setq x (red x)))
- ((%funcall compare-function (le y) (le x))
- (collect-term (le y) (lc y))
- (setq y (red y)))
- (t (setq sum (+ (lc x) (lc y)))
- (unless (0? sum)
- (collect-term (le x) sum))
- (setq x (red x) y (red y))))))))
-
- (defmethod minus ((x epolynomial))
- (let ((domain (domain-of x)))
- (bind-domain-context domain
- (make-instance 'epolynomial
- :domain domain
- :compare-function (slot-value x 'compare-function)
- :form (gterms-minus (poly-form x))))))
-
- (defun gterms-minus (x)
- (map-over-each-term x (e c)
- (collect-term e (- c))))
-
- (defmethod-binary difference epolynomial (x y)
- (same-compare-functions (x y)
- (bind-domain-context domain
- (make-instance 'epolynomial
- :domain domain
- :compare-function compare-function
- :form (gterms-difference compare-function (poly-form x) (poly-form y))))))
-
- (defun gterms-difference (compare-function x y) ;x and y are term lists
- (let ((ans-terms (list nil))
- (terms nil)
- sum)
- (macrolet
- ((collect-term (.e. .c.)
- `(progn (setf (rest terms) (make-terms , .e. , .c.))
- (setf terms (rest terms)))))
- (setq terms ans-terms)
- (loop
- (cond ((terms0? x)
- (cond ((terms0? y) (return (rest ans-terms)))
- (t (collect-term (le y) (- (lc y)))
- (setq y (red y)))))
- ((or (terms0? y)
- (%funcall compare-function (le x) (le y)))
- (collect-term (le x) (lc x))
- (setq x (red x)))
- ((%funcall compare-function (le y) (le x))
- (collect-term (le y) (- (lc y)))
- (setq y (red y)))
- (t (setq sum (- (lc x) (lc y)))
- (unless (0? sum)
- (collect-term (le x) sum))
- (setq x (red x) y (red y))))))))
-
-
- (defmethod-binary times epolynomial (x y)
- (same-compare-functions (x y)
- (bind-domain-context domain
- (make-instance 'epolynomial
- :domain domain
- :compare-function compare-function
- :form (gterms-times compare-function (poly-form x) (poly-form y))))))
-
- (defun gterms-mon-times (poly-terms e c)
- (if (0? c) (terms0)
- (map-over-each-term poly-terms (te tc)
- (collect-term (+ e te) (* tc c)))))
-
- (defun gterms-times (compare-function x y)
- (let (;; Multiply x by the first term of y. This is the initial
- ;; term list we will modify.
- (answer (gterms-mon-times x (le y) (lc y)))
- e c)
- (setq answer (cons nil answer))
- (loop for (e-y . c-y) in (red y)
- for ans = answer do
- (loop for (e-x . c-x) in x do
- (unless (0? (setq c (* c-x c-y)))
- (setq e (+ e-x e-y))
- ;; Find place to insert this term.
- (loop for red-ans = (red ans) do
- ;; Sure would be nice if the complier recognized and optimized
- ;; the usages of (red ans)
- (cond ((or (terms0? red-ans)
- (%funcall compare-function e (le red-ans)))
- (setf (red ans) (make-terms e c red-ans))
- (return t))
- ((= e (le red-ans))
- (setf (lc red-ans) (+ (lc red-ans) c))
- (return t))
- (t (setq ans red-ans)))))))
- (loop for ans on answer
- do (when (and (red ans) (0? (lc (red ans))))
- (setf (red ans) (red (red ans)))))
- (red answer)))
-